package tool

// by daoyi
import (
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt"
	"github.com/golang-jwt/jwt/request"
	"log"
	"reflect"
	"time"
)

type TokenInfo struct {
	Id       uint
	Name     string
	RoleName string
	Type     int
	GameId   int
	jwt.StandardClaims
}

type TokenApiInfo struct {
	Id   uint
	Name string
	jwt.StandardClaims
}

const TokenExpireDuration = time.Hour * 24 * 2 //过期时间 2天
var Secret = []byte("my name is hanmeimei")    //Secret(盐) 用来加密解密

// 生成 admin后台 jwt token
func GenToken(ID uint, Name string, Type int, GameId int, RoleName string) (string, error) {
	var claims = TokenInfo{
		ID,
		Name,
		RoleName,
		Type,
		GameId,
		jwt.StandardClaims{
			ExpiresAt: time.Now().Add(TokenExpireDuration).Unix(), // 过期时间
			Issuer:    "zhaohaiyu",                                // 签发人
		},
	}
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	signedToken, err := token.SignedString([]byte(Secret))
	if err != nil {
		log.Println("生成token失败:", err)
		return "", fmt.Errorf("生成token失败:%v", err)
	}
	return signedToken, nil
}

// 生成 Api前端接口jwt token
func GenApiToken(ID uint, Name string) (string, error) {
	var claims = TokenApiInfo{
		ID,
		Name,
		jwt.StandardClaims{
			ExpiresAt: time.Now().Add(TokenExpireDuration).Unix(), // 过期时间
			Issuer:    "zhaohaiyu",                                // 签发人
		},
	}
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	signedToken, err := token.SignedString([]byte(Secret))
	if err != nil {
		log.Println("生成token失败:", err)
		return "", fmt.Errorf("生成token失败:%v", err)
	}
	return signedToken, nil
}

// 验证 jwt token
func ParseToken(tokenStr string) (*TokenInfo, error) {
	token, err := jwt.ParseWithClaims(tokenStr, &TokenInfo{}, func(token *jwt.Token) (i interface{}, err error) { // 解析token
		return Secret, nil
	})
	if err != nil {
		log.Println(err)
		return nil, err
	}
	if claims, ok := token.Claims.(*TokenInfo); ok && token.Valid { // 校验token
		return claims, nil
	}
	return nil, errors.New("invalid token")
}

// 验证 Api前端接口 jwt token
func ParseApiToken(tokenStr string) (*TokenApiInfo, error) {
	token, err := jwt.ParseWithClaims(tokenStr, &TokenApiInfo{}, func(token *jwt.Token) (i interface{}, err error) { // 解析token
		return Secret, nil
	})
	if err != nil {
		log.Println(err)
		return nil, err
	}
	if claims, ok := token.Claims.(*TokenApiInfo); ok && token.Valid { // 校验token
		fmt.Println(claims)
		return claims, nil
	}
	return nil, errors.New("invalid token")
}

// 从请求头中获取token
func GetTokenFromRequest(c *gin.Context) (token *jwt.Token, err error) {
	token, err = request.ParseFromRequest(c.Request, request.AuthorizationHeaderExtractor,
		func(token *jwt.Token) (interface{}, error) {
			return Secret, nil
		})
	return token, err
}

// 根据key从载荷中获取数据
func GetValueFromTokenClaims(key string, claims jwt.Claims) string {
	v := reflect.ValueOf(claims)
	if v.Kind() == reflect.Map {
		for _, k := range v.MapKeys() {
			value := v.MapIndex(k)

			if fmt.Sprintf("%s", k.Interface()) == key {
				return fmt.Sprintf("%v", value.Interface())
			}
		}
	}
	return ""
}

// 解析token
func outToken(tokenString string) (*jwt.Token, *TokenInfo, error) {
	claims := &TokenInfo{}

	token, err := jwt.ParseWithClaims(tokenString, claims, func(t *jwt.Token) (interface{}, error) {
		return Secret, nil
	})

	return token, claims, err
}

func JwtParseToken(tokenString string, keys ...string) (map[string]string, bool) {

	token, _ := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
		}
		return Secret, nil
	})
	if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
		mapData := make(map[string]string)
		for index, val := range claims {
			mapData[index] = fmt.Sprintf("%v", val)
		}
		return mapData, true
	} else {
		return nil, false
	}
}
